/*
 * Viewer.cpp
 *
 *  Created on: 26.01.2010
 *      Author: Admin
 */

#include "Viewer.h"

Viewer::Viewer()
{
	SetFitMode(FIT_NOT);
	SetScaleline((double*) DEFSCALELINE);
	SetClipRect((irect*) &DEFCLIPRECT);
	Zoom100();
	CalcFitScale();
	SetMoveStep(MOVESPET_SCREEN);
	MoveAlign(ALIGN_CENTER | VALIGN_MIDDLE);
}

Viewer::~Viewer()
{
}

void Viewer::Draw()
{
	if (_image != NULL)
	{
		Log::msg("Width: %d, height: %d, depth: %d, scale: %.2f", _image->width, _image->height, _image->depth,
				GetScale());
		icanvas* c = GetCanvas();
		Log::msg("x: %d, y: %d, x2: %d, y2: %d", c->clipx1, c->clipy1, c->clipx2, c->clipy2);
		StretchBitmap(_imagerect.x, _imagerect.y, _imagerect.w, _imagerect.h, _image, 0);
	}
	else
		Log::msg("Current is NULL!");
}

void Viewer::SetClipRect(int x, int y, int w, int h)
{
	_cliprect.x = x;
	_cliprect.y = y;
	_cliprect.w = w;
	_cliprect.h = h;
}

void Viewer::SetImage(ibitmap* bit)
{
	_scale = 1.0;
	_fitscale = 1.0;
	_imagerect = _cliprect;
	_image = bit;
	CalcFitScale();
	ZoomFit();
	if (_imagerect.w <= _cliprect.w)
		MoveAlign(ALIGN_CENTER);
	else
		MoveAlign(ALIGN_LEFT);
	if (_imagerect.h <= _cliprect.h)
		MoveAlign(VALIGN_MIDDLE);
	else
		MoveAlign(VALIGN_TOP);
}

void Viewer::SetScale(double scale)
{
	_scale = scale;
	if (_image != NULL)
	{
		_imagerect.w = (int) (_image->width * scale);
		_imagerect.h = (int) (_image->height * scale);
		if (_imagerect.w <= _cliprect.w && _imagerect.h <= _cliprect.h)
		{
			MoveAlign(VALIGN_MIDDLE | ALIGN_CENTER);
		}
		else
		{
			Move(0, 0); // заглушка для корректировки выхода за границы изображения
			// TODO: нормальный расчет центральной точки при увеличении и уменьшении
			// int vx = (int)((_cliprect.w / 2 + _cliprect.x - _imagerect.x) * (scale / _scale - 1));
			// int vy = (int)((_cliprect.h / 2 + _cliprect.y - _imagerect.y) * (scale / _scale - 1));
			// Move(-vx, -vy);
			// Log::msg("vx %d, vy %d",-vx,-vy);
			if (_imagerect.w <= _cliprect.w)
				MoveAlign(ALIGN_CENTER);
			if (_imagerect.h <= _cliprect.h)
				MoveAlign(VALIGN_MIDDLE);
		}
	}
	else
		_scale = scale;
}

bool Viewer::CanZoomIn()
{
	if (_scaleline != NULL)
	{
		if (_scale < _fitscale)
			return true;
		int i = 0;
		while (_scaleline[i] != 0)
			i++;
		if (_scale < _scaleline[i-1])
			return true;
	}
	return false;
}

bool Viewer::CanZoomOut()
{
	if (_scaleline != NULL && (_scale > _fitscale || _scale > _scaleline[0]))
		return true;
	return false;
}

void Viewer::ZoomIn() //TODO: Сделать правильное увеличение для масштаба заполнения большего, чем максимум в линейке
{
	if (_scaleline != NULL)
	{
		for (unsigned int i = 0; _scaleline[i] != 0; i++)
		{
			if (_scaleline[i] <= _scale)
				continue;
			if (_scale < _fitscale && _fitscale < _scaleline[i])
				SetScale(_fitscale);
			else
				SetScale(_scaleline[i]);
			break;
		}
	}
}

void Viewer::ZoomOut()
{
	if (_scaleline != NULL)
	{
		double temp = 0;
		for (unsigned int i = 0; _scaleline[i] != 0; i++)
		{
			if (_scaleline[i] < _scale)
			{
				temp = _scaleline[i];
				continue;
			}
			if (_scale > _fitscale && _fitscale > temp)
				SetScale(_fitscale);
			else
				SetScale(temp);
			break;
		}
	}
}

void Viewer::Zoom(int num)
{
	if (_scaleline != NULL)
		for (int i = 0; _scaleline[i] != 0; i++)
			if (i == num)
			{
				SetScale(_scaleline[num]);
				break;
			}
}

void Viewer::CalcFitScale()
{
	if (_image != NULL)
		if (_fitmode == FIT_WIDTH || (_fitmode == (FIT_WIDTH | FIT_OVERSIZE) && _image->width > _cliprect.w))
			_fitscale = (_cliprect.w / (float) _image->width);
		else if (_fitmode == FIT_HEIGHT || (_fitmode == (FIT_HEIGHT | FIT_OVERSIZE) && _image->height > _cliprect.h))
			_fitscale = (_cliprect.h / (float) _image->height);
		else if (_fitmode == FIT_BOTH || (_fitmode == (FIT_BOTH | FIT_OVERSIZE) && (_image->width > _cliprect.w
				|| _image->height > _cliprect.h)))
			_fitscale = (_image->width/_cliprect.w > _image->height/_cliprect.h ? _cliprect.w / (double) _image->width : _cliprect.h
					/ (double) _image->height);
		else
			_fitscale = (1.0);
	else
		_fitscale = (1.0);
}

bool Viewer::CanMove(int dx, int dy)
{
	if (dx == 0 || (dx < 0 && _imagerect.x <= _cliprect.x + dx) || (dx > 0 && _imagerect.x + _imagerect.w
			>= _cliprect.x + _cliprect.w + dx))
		if (dy == 0 || (dy < 0 && _imagerect.y <= _cliprect.y + dy) || (dy > 0 && _imagerect.y + _imagerect.h
				>= _cliprect.y + _cliprect.h + dy))
			return true;
	return false;
}

void Viewer::Move(int dx, int dy)
{
	_imagerect.x -= dx;
	_imagerect.y -= dy;
	if (_imagerect.x > _cliprect.x &&
			_imagerect.w > _cliprect.w)
		_imagerect.x = _cliprect.x;
	if (_imagerect.x < _cliprect.w - _imagerect.w + _cliprect.x &&
			_imagerect.w > _cliprect.w)
		_imagerect.x = _cliprect.w - _imagerect.w + _cliprect.x;
	if (_imagerect.y > _cliprect.y &&
			_imagerect.h > _cliprect.h)
		_imagerect.y = _cliprect.y;
	if (_imagerect.y < _cliprect.h - _imagerect.h + _cliprect.y &&
			_imagerect.h > _cliprect.h)
		_imagerect.y = _cliprect.h - _imagerect.h + _cliprect.y;
}

bool Viewer::CanMoveDirection(int direction)
{
	if (direction & DIRECTION_UP && CanMove(0, -1))
		return true;
	if (direction & DIRECTION_DOWN && CanMove(0, 1))
		return true;
	if (direction & DIRECTION_LEFT && CanMove(-1, 0))
		return true;
	if (direction & DIRECTION_RIGHT && CanMove(1, 0))
		return true;
	return false;
}

void Viewer::MoveDirection(int direction)
{
	if (CanMoveDirection(direction))
	{
		int dx = 0, dy = 0;
		if (direction & DIRECTION_UP)
			dy -= (int) (_cliprect.h * _movestep);
		if (direction & DIRECTION_DOWN)
			dy += (int) (_cliprect.h * _movestep);
		if (direction & DIRECTION_LEFT)
			dx -= (int) (_cliprect.w * _movestep);
		if (direction & DIRECTION_RIGHT)
			dx += (int) (_cliprect.w * _movestep);
		Move(dx, dy);
	}
}

void Viewer::MoveAlign(int align)
{
	if (align & ALIGN_LEFT)
		_imagerect.x = _cliprect.x;
	else if (align & ALIGN_CENTER)
		_imagerect.x = _cliprect.x + (_cliprect.w - _imagerect.w) / 2;
	else if (align & ALIGN_RIGHT)
		_imagerect.x = _cliprect.x + _cliprect.w - _imagerect.w;
	if (align & VALIGN_TOP)
		_imagerect.y = _cliprect.y;
	else if (align & VALIGN_MIDDLE)
		_imagerect.y = _cliprect.y + (_cliprect.h - _imagerect.h) / 2;
	else if (align & VALIGN_BOTTOM)
		_imagerect.y = _cliprect.y + _cliprect.h - _imagerect.h;
}
